package com.app.shop.service.weixin.impl;


import com.app.shop.dao.wg.WgOrderMapper;
import com.app.shop.entity.WgOrder;
import com.app.shop.entity.weixin.WxPayInfo;
import com.app.shop.entity.weixin.WxPayResult;
import com.app.shop.enums.OrderStatusEnum;
import com.app.shop.enums.PayTypeEnum;
import com.app.shop.service.shop.WgOrderService;
import com.app.shop.service.shop.impl.WgOrderServiceImp;
import com.app.shop.service.weixin.WeixinService;
import com.app.shop.util.PropertyAccessor;
import com.app.shop.util.weixin.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.app.shop.constants.WeixinConstants.WEIXINPARAMS;
import org.apache.log4j.Logger;
import java.util.Date;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;


/**
 * @Title
 * @Description (微信服务接口)
 * @author Garfield Miao
 * @date 2019年25月51日
 * @upAuthor Garfield Miao
 * @update 2019年25月51日
 */
@Service("weixinService")
public class WeixinServiceImp implements WeixinService {

    private static final Logger LOG = Logger.getLogger(WgOrderServiceImp.class);

    @Autowired
    private WgOrderMapper wgCommodityMapper;
    @Autowired
    private WgOrderService orderService;


    @Override
    public WxPayInfo getPrepayid(String openId, Integer orderId, String amount, String spbill_create_ip, String body) throws Exception {
        // TODO 获取getPrepayid
        WeixinUtil weixinUtil = new WeixinUtil();
        // 1 参数
        // 附加数据 原样返回
        String attach = "";
        // 总金额以分为单位，不带小数点
        String totalFee = weixinUtil.getMoney(amount);
        String appid=null;
        String appsecret=null;
        // 商户号
        String mch_id =null;
        String mch_idKey=null;
        WxPayInfo wxPayInfo =new WxPayInfo();
        appid= PropertyAccessor.getProperty(WEIXINPARAMS.APPXJSAPIID.getCode());
        appsecret=PropertyAccessor.getProperty(WEIXINPARAMS.APPXJSAPISECRET.getCode());
        mch_id = PropertyAccessor.getProperty(WEIXINPARAMS.PARTNERJSAPI.getCode());
        mch_idKey=PropertyAccessor.getProperty(WEIXINPARAMS.PARTNERJSAPIKEY.getCode());
        // 这里notify_url是 支付完成后微信发给该链接信息，可以判断会员是否支付成功，改变订单状态等。
        String notify_url= PropertyAccessor.getProperty("fileHttpPath")+PropertyAccessor.getProperty(WEIXINPARAMS.NOTIFYURL.getCode());
        String paySpaceTime="10";
        Date now = new Date();
        String time_start =TenpayUtil.getStartCurrTime(now);
        String time_expire=TenpayUtil.getStartCurrTime(now);
        //判断订单是否可以支付
        WgOrder wgOrder = wgCommodityMapper.selectByPrimaryKey(orderId);
        if(!OrderStatusEnum.NOTPAYORDER_STATUS_ENUM.equals(wgOrder.getStatus())){
            throw new Exception("该订单不能支付");
        }
        //代码待插入
        String  trade_type="JSAPI";
        // 随机字符串
        String nonce_str = weixinUtil.getNonceStr();

        // 商户订单号
        String out_trade_no = wgOrder.getOrderCode();
        SortedMap<String, String> packageParams = new TreeMap<String, String>();
        String prepay_id = "";
        RequestHandler reqHandler = new RequestHandler(null, null);
        packageParams.put("appid", appid);
        packageParams.put("mch_id", mch_id);
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("body", body);
        packageParams.put("attach", attach);
        packageParams.put("out_trade_no", out_trade_no);
        packageParams.put("total_fee", totalFee);
        packageParams.put("time_expire", time_expire);
        packageParams.put("time_start", time_start);
        packageParams.put("spbill_create_ip", spbill_create_ip);
        packageParams.put("notify_url", notify_url);
        packageParams.put("trade_type", trade_type);
        packageParams.put("openid", openId);

        reqHandler.init(appid, appsecret, mch_idKey);
        String xml= WXPayUtil.generateSignedXml(packageParams, mch_idKey);
        LOG.info("获取到的预支付拼接的微信方法xml：" + xml);
        String createOrderURL = PropertyAccessor.getProperty(WEIXINPARAMS.CREATEORDERURL.getCode());
        prepay_id = new GetWxOrderno().getPayNo(createOrderURL, xml);
        if(prepay_id.indexOf("#ERROR")!=-1){
            if(prepay_id.equals("ORDERPAID#ERROR")){
                throw new Exception("微信已支付，请勿重新支付");
            }
            throw new Exception("微信支付异常");
        }

        LOG.info("获取到的预支付ID：" + prepay_id);
        //生成签名准备工作
        SortedMap<String, String> finalpackage = new TreeMap<String, String>();
        String finalsign=null;
        String timestamp = Sha1Util.getTimeStamp();
        finalpackage.put("appId", appid);
        finalpackage.put("timeStamp", timestamp);
        finalpackage.put("nonceStr", nonce_str);
        finalpackage.put("package", "prepay_id="+prepay_id);
        finalpackage.put("signType", "MD5");
        //生成签名
        finalsign = reqHandler.createSign(finalpackage);
        wxPayInfo.setAppid(appid);
        wxPayInfo.setNoncestr(nonce_str);
        wxPayInfo.setPackages(PropertyAccessor.getProperty(WEIXINPARAMS.PACKAGES.getCode()));
        wxPayInfo.setPartnerid(mch_id);
        wxPayInfo.setPrepayid(prepay_id);
        wxPayInfo.setSign(finalsign);
        wxPayInfo.setTimestamp(timestamp);

        return wxPayInfo;

    }

    @Override
    public String payCallBack(String notityXml) throws Exception {
        // TODO 微信支付回调处理
        String resXml= "";
        try {
            String RETURN_CODE = "return_code";
            String return_code = "";
            Map<String, String> respData = WXPayUtil.xmlToMap(notityXml);
            if (respData.containsKey(RETURN_CODE)) {
                return_code = respData.get(RETURN_CODE);
            } else {
                LOG.error(String.format("No `return_code` in XML: %s", notityXml));
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[No `return_code` in XML]]></return_msg>" + "</xml> ";
            }
            if (return_code.equals(WXPayConstants.FAIL)) {
                LOG.error(String.format("PAY FAIL", notityXml));
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[PAY FAIL]]></return_msg>" + "</xml> ";
            } else if (return_code.equals(WXPayConstants.SUCCESS)) {

                if (this.isResponseSignatureValid(respData)) {
                    //验签成功进行处理
                    //支付成功
                    WxPayResult wpr = new WxPayResult();
                    wpr.setAppid(respData.get("appid").toString());
                    wpr.setBankType(respData.get("bank_type").toString());
                    wpr.setCashFee(respData.get("cash_fee").toString());
                    wpr.setFeeType(respData.get("fee_type").toString());
                    wpr.setIsSubscribe(respData.get("is_subscribe").toString());
                    wpr.setMchId(respData.get("mch_id").toString());
                    wpr.setNonceStr(respData.get("nonce_str").toString());
                    wpr.setOpenid(respData.get("openid").toString());
                    wpr.setOutTradeNo(respData.get("out_trade_no").toString());
                    wpr.setResultCode(respData.get("result_code").toString());
                    wpr.setReturnCode(respData.get("return_code").toString());
                    wpr.setSign(respData.get("sign").toString());
                    wpr.setTimeEnd(respData.get("time_end").toString());
                    wpr.setTotalFee(respData.get("total_fee").toString());
                    wpr.setTradeType(respData.get("trade_type").toString());
                    wpr.setTransactionId(respData.get("transaction_id").toString());
                    WgOrder order = wgCommodityMapper.selectByOrderCode(wpr.getOutTradeNo());
                    LOG.info("orderCode:"+wpr.getOutTradeNo());
                    if (order == null) {
                        throw new Exception("订单号不存在");
                    }
                    WeixinUtil weixinUtil = new WeixinUtil();
                    String armos =weixinUtil.getMoneyYuan(wpr.getTotalFee());
                    String totalFee = weixinUtil.getMoney(order.getPayPrice().toString());
                    if(totalFee.equals(wpr.getTotalFee())){
                        //订单状态判断
                        if (OrderStatusEnum.NOTPAYORDER_STATUS_ENUM.equals(order.getStatus())) {
                            //如果已支付，向transaction中保存数据
                            if(OrderStatusEnum.CANCELORDER_STATUS_ENUM.equals(order.getStatus())||
                                    OrderStatusEnum.USEDORDER_STATUS_ENUM.equals(order.getStatus())||
                                    OrderStatusEnum.PAYEDORDER_STATUS_ENUM.equals(order.getStatus())){
                            orderService.saveTransaction(order.getId(),
                                    armos, PayTypeEnum.WEIXIN.value(),"SUCCESS");
                            }
                            LOG.info(String.format("order(orderId=%s) has paid by paySucess", wpr.getOutTradeNo()));
                        }else{
                            /** Save Transaction */
                        orderService.saveTransaction(order.getId(),
                                    armos, PayTypeEnum.WEIXIN.value(),"SUCCESS");
//
                        orderService.paySuccess(order,
                                armos,"SUCCESS");
                        }

                    }else{
                        LOG.error("微信回调金额异常FAIL---orderId："+order.getId()+"&price="+wpr.getTotalFee());
                    }

                    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                } else {
                    LOG.error(String.format(
                            "Invalid sign value in XML: %s", notityXml));
                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                            + "<return_msg><![CDATA[Invalid sign value in XML]]></return_msg>" + "</xml> ";
                }

            }else {
                LOG.error(String.format(
                        "return_code value %s is invalid in XML: %s", return_code,
                        notityXml));
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[return_code FAIL ]]></return_msg>" + "</xml> ";
            }
        } catch (Exception e) {
            LOG.error("微信支付异常", e);
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[[PAY FAIL ]]></return_msg>" + "</xml> ";
        }

        return resXml;
    }

    /**
     * 判断xml数据的sign是否有效，必须包含sign字段，否则返回false。
     *
     * @param reqData 向wxpay post的请求数据
     * @return 签名是否有效
     * @throws Exception
     */
    private boolean isResponseSignatureValid(Map<String, String> reqData) throws Exception {
        // 返回数据的签名方式和请求中给定的签名方式是一致的
        String appid = reqData.get("appid").toString();
        String mch_idKey = PropertyAccessor.getProperty(WEIXINPARAMS.PARTNERJSAPIKEY.getCode());
        return WXPayUtil.isSignatureValid(reqData, mch_idKey, WXPayConstants.SignType.MD5);
    }



}
